﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace KcpLib;

class ByteBuffer //: ICloneable
{
    //字节缓存区
    private byte[] buf;
    //读取索引
    private int readIndex = 0;
    //写入索引
    private int writeIndex = 0;
    //读取索引标记
    private int markReadIndex = 0;
    //写入索引标记
    private int markWirteIndex = 0;
    //缓存区字节数组的长度
    private int capacity;

    //对象池
    private static List<ByteBuffer> pool = new List<ByteBuffer>();
    private static int poolMaxCount = 200;

    //此对象是否池化
    private bool isPool = false;

    /// <summary>
    /// 构造方法
    /// </summary>
    /// <param name="capacity">初始容量</param>
    private ByteBuffer(int capacity)
    {
        this.buf = new byte[capacity];
        this.capacity = capacity;
        this.readIndex = 0;
        this.writeIndex = 0;
    }


    /// <summary>
    /// 构建一个capacity长度的字节缓存区ByteBuffer对象
    /// </summary>
    /// <param name="capacity">初始容量</param>
    /// <param name="fromPool">
    /// true表示获取一个池化的ByteBuffer对象，池化的对象必须在调用Dispose后才会推入池中，此方法为线程安全的。
    /// 当为true时，从池中获取的对象的实际capacity值。
    /// </param>
    /// <returns>ByteBuffer对象</returns>
    public static ByteBuffer Allocate(int capacity, bool fromPool = false)
    {
        if (!fromPool)
        {
            return new ByteBuffer(capacity);
        }
        lock (pool)
        {
            ByteBuffer bbuf;
            if (pool.Count == 0)
            {
                bbuf = new ByteBuffer(capacity)
                {
                    isPool = true
                };
                return bbuf;
            }
            int lastIndex = pool.Count - 1;
            bbuf = pool[lastIndex];
            pool.RemoveAt(lastIndex);
            if (!bbuf.isPool)
            {
                bbuf.isPool = true;
            }
            return bbuf;
        }
    }
    
    
    /// <summary>
    /// 将bytes字节数组从startIndex开始的length字节写入到此缓存区
    /// </summary>
    /// <param name="bytes">待写入的字节数据</param>
    /// <param name="startIndex">写入的开始位置</param>
    /// <param name="length">写入的长度</param>
    public void WriteBytes(byte[] bytes, int startIndex, int length)
    {
        if (length <= 0 || startIndex < 0) return;

        int total = length + writeIndex;
        int len = buf.Length;
        // FixSizeAndReset(len, total);
        Array.Copy(bytes, startIndex, buf, writeIndex, length);
        writeIndex = total;
    }

    /// <summary>
    /// 设置/获取读指针位置
    /// </summary>
    public int ReaderIndex
    {
        get
        {
            return readIndex;
        }
        set
        {
            if (value < 0) return;
            readIndex = value;
        }
    }

    /// <summary>
    /// 设置/获取写指针位置
    /// </summary>
    public int WriterIndex
    {
        get
        {
            return writeIndex;
        }
        set
        {
            if (value < 0) return;
            writeIndex = value;
        }
    }

    /// <summary>
    /// 可读的有效字节数
    /// </summary>
    /// <returns>可读的字节数</returns>
    public int ReadableBytes
    {
        get
        {
            return writeIndex - readIndex;
        }
    }

    /// <summary>
    /// 可写的剩余空间数
    /// </summary>
    /// <returns>可写的字节数</returns>
    public int WritableBytes
    {
        get
        {
            return capacity - writeIndex;
        }
    }

    public byte[] RawBuffer
    {
        get
        {
            return buf;
        }
    }
    
    /// <summary>
    /// 清空此对象，但保留字节缓存数组（空数组）
    /// </summary>
    public void Clear()
    {
        readIndex = 0;
        writeIndex = 0;
        markReadIndex = 0;
        markWirteIndex = 0;
        capacity = buf.Length;
    }

    /// <summary>
    /// 释放对象，清除字节缓存数组，如果此对象为可池化，那么调用此方法将会把此对象推入到池中等待下次调用
    /// </summary>
    public void Dispose()
    {
        if (isPool) {
            lock (pool) {
                if (pool.Count < poolMaxCount) {
                    this.Clear();
                    pool.Add(this);
                    return;
                }
            }
        }

        readIndex = 0;
        writeIndex = 0;
        markReadIndex = 0;
        markWirteIndex = 0;
        capacity = 0;
        buf = null;
    }
}